#include <QString>
#include <QtTest>
#include <QSignalSpy>
#include <QVariant>

#include "test_ActionListController.h"
#include "MediaListModel.h"
#include "MockMediaSourceFactory.h"
#include "ActionListController.h"
#include "modelViewRules.h"


test_ActionListController::test_ActionListController()
{
}

/** executed before every test case */
void test_ActionListController::init()
{
   /* this applies to any concrete child of QAbstractItemModel */
   MockMediaSourceFactory *factory = new MockMediaSourceFactory();
   m_model = new MediaListModel( factory, this);
   m_actionController = new ActionListController( *m_model, this);
}

/** executed after every test case */
void test_ActionListController::cleanup()
{
   delete m_actionController;
   delete m_model;
}

void test_ActionListController::initTestCase()
{
}

void test_ActionListController::cleanupTestCase()
{
}

void test_ActionListController::testInstantiation()
{
   QVERIFY( m_model != NULL);
   QVERIFY( m_actionController != NULL);

   QCOMPARE( m_actionController->activeItemRow(), ActionListController::NoItemActive);
}

/**
 * activate a valid item
 */
void test_ActionListController::testActivateItem()
{
   QSignalSpy activeChangedSpy( m_actionController, SIGNAL(activeRowChanged(int)) );

   m_model->addMediaFile("c:/Fake/Path.mp3");

   m_actionController->activateRequest( m_model->index(0));
   QCOMPARE( m_actionController->activeItemRow(), 0);
   QCOMPARE( activeChangedSpy.count(), 1);
   QCOMPARE( activeChangedSpy.at(0).at(0).toInt(), 0);
}

/**
 * try to activate an invalid row, after a valid one was active.
 */
void test_ActionListController::testActivateInvalid()
{
   QSignalSpy activeChangedSpy( m_actionController, SIGNAL(activeRowChanged(int)) );

   m_model->addMediaFile("c:/Fake/Path.mp3");

   m_actionController->activateRequest( m_model->index(0));
   m_actionController->activateRequest( m_model->index(5));
   QCOMPARE( m_actionController->activeItemRow(), ActionListController::NoItemActive);
   QCOMPARE( activeChangedSpy.count(), 2);
   QCOMPARE( activeChangedSpy.at(1).at(0).toInt(), ActionListController::NoItemActive);
}

void test_ActionListController::testShiftItemUp()
{
   QSignalSpy shiftedUpSpy( m_actionController, SIGNAL(shiftedUp(int)) );

   m_model->addMediaFile("c:/Fake/Path/track1.mp3");
   m_model->addMediaFile("c:/Fake/Path/track2.mp3");

   m_actionController->shiftItemUp( 1);

   QString stringId1st = m_model->index(0).data( modelViewRules::StringId).toString();
   QString stringId2nd = m_model->index(1).data( modelViewRules::StringId).toString();

   QCOMPARE( stringId1st, QString("track2.mp3"));
   QCOMPARE( stringId2nd, QString("track1.mp3"));
   QCOMPARE( shiftedUpSpy.count(), 1);
   /* shifted to 0 */
   QCOMPARE( shiftedUpSpy.at(0).at(0).toInt(), 0);
}

/**
 * try to shift up the first element of model
 */
void test_ActionListController::testShiftFirstItemUp()
{
   QSignalSpy shiftedUpSpy( m_actionController, SIGNAL(shiftedUp(int)) );
   m_model->addMediaFile("c:/Fake/Path/track1.mp3");

   m_actionController->shiftItemUp( 0);

   QCOMPARE( shiftedUpSpy.count(), 0);
}

/**
 * try to shift a non existent item
 */
void test_ActionListController::testShiftInvalidItemUp()
{
   QSignalSpy shiftedUpSpy( m_actionController, SIGNAL(shiftedUp(int)) );
   m_model->addMediaFile("c:/Fake/Path/track1.mp3");

   m_actionController->shiftItemUp( 5);
   m_actionController->shiftItemUp( -5);

   QCOMPARE( shiftedUpSpy.count(), 0);
}

void test_ActionListController::testShiftItemDown()
{
   QSignalSpy shiftedDownSpy( m_actionController, SIGNAL(shiftedDown(int)) );

   m_model->addMediaFile("c:/Fake/Path/track1.mp3");
   m_model->addMediaFile("c:/Fake/Path/track2.mp3");

   m_actionController->shiftItemDown( 0);

   QString stringId1st = m_model->index(0).data( modelViewRules::StringId).toString();
   QString stringId2nd = m_model->index(1).data( modelViewRules::StringId).toString();

   QCOMPARE( stringId1st, QString("track2.mp3"));
   QCOMPARE( stringId2nd, QString("track1.mp3"));
   QCOMPARE( shiftedDownSpy.count(), 1);
   /* shifted to 0 */
   QCOMPARE( shiftedDownSpy.at(0).at(0).toInt(), 1);
}

void test_ActionListController::testShiftLastItemDown()
{
   QSignalSpy shiftedDownSpy( m_actionController, SIGNAL(shiftedDown(int)) );
   m_model->addMediaFile("c:/Fake/Path/track1.mp3");

   m_actionController->shiftItemDown( 0);

   QCOMPARE( shiftedDownSpy.count(), 0);
}

/**
 * try to shift a non existent item
 */
void test_ActionListController::testShiftInvalidItemDown()
{
   QSignalSpy shiftedDownSpy( m_actionController, SIGNAL(shiftedDown(int)) );
   m_model->addMediaFile("c:/Fake/Path/track1.mp3");

   m_actionController->shiftItemDown( 5);
   m_actionController->shiftItemDown( -5);

   QCOMPARE( shiftedDownSpy.count(), 0);
}

/**
 * shift active item one position up
 */
void test_ActionListController::testShiftActiveItemUp()
{
   QSignalSpy activeChangedSpy( m_actionController, SIGNAL(activeRowChanged(int)) );

   m_model->addMediaFile("c:/Fake/Path/track1.mp3");
   m_model->addMediaFile("c:/Fake/Path/track2.mp3");

   m_actionController->activateRequest( m_model->index(1));
   m_actionController->shiftItemUp(1);

   QCOMPARE( activeChangedSpy.count(), 2);
   QCOMPARE( activeChangedSpy.at(0).at(0).toInt(), 1);
   QCOMPARE( activeChangedSpy.at(1).at(0).toInt(), 0);
}

/**
 * shift up the item below the active one. Active row changes
 * to new active item position
 */
void test_ActionListController::testShiftUpAndChangeActive()
{
   QSignalSpy activeChangedSpy( m_actionController, SIGNAL(activeRowChanged(int)) );

   m_model->addMediaFile("c:/Fake/Path/track1.mp3");
   m_model->addMediaFile("c:/Fake/Path/track2.mp3");

   m_actionController->activateRequest( m_model->index(0));
   m_actionController->shiftItemUp(1);

   QCOMPARE( activeChangedSpy.count(), 2);
   QCOMPARE( activeChangedSpy.at(0).at(0).toInt(), 0);
   QCOMPARE( activeChangedSpy.at(1).at(0).toInt(), 1);
}

void test_ActionListController::testShiftActiveItemDown()
{
   QSignalSpy activeChangedSpy( m_actionController, SIGNAL(activeRowChanged(int)) );

   m_model->addMediaFile("c:/Fake/Path/track1.mp3");
   m_model->addMediaFile("c:/Fake/Path/track2.mp3");

   m_actionController->activateRequest( m_model->index(0));
   m_actionController->shiftItemDown(0);

   QCOMPARE( activeChangedSpy.count(), 2);
   QCOMPARE( activeChangedSpy.at(0).at(0).toInt(), 0);
   QCOMPARE( activeChangedSpy.at(1).at(0).toInt(), 1);
}

/**
 * shift down the item above the active one. Active row changes
 * to new active item position
 */
void test_ActionListController::testShiftDownAndChangeActive()
{
   QSignalSpy activeChangedSpy( m_actionController, SIGNAL(activeRowChanged(int)) );

   m_model->addMediaFile("c:/Fake/Path/track1.mp3");
   m_model->addMediaFile("c:/Fake/Path/track2.mp3");

   m_actionController->activateRequest( m_model->index(1));
   m_actionController->shiftItemDown(0);

   QCOMPARE( activeChangedSpy.count(), 2);
   QCOMPARE( activeChangedSpy.at(0).at(0).toInt(), 1);
   QCOMPARE( activeChangedSpy.at(1).at(0).toInt(), 0);
}

/**
 * removing a row above active item. This changes active item row.
 */
void test_ActionListController::testRemoveRowChangesActiveItem()
{
   QSignalSpy activeChangedSpy( m_actionController, SIGNAL(activeRowChanged(int)) );

   m_model->addMediaFile("c:/Fake/Path/track1.mp3");
   m_model->addMediaFile("c:/Fake/Path/track2.mp3");

   m_actionController->activateRequest( m_model->index(1));
   m_model->removeRow( 0);

   QCOMPARE( activeChangedSpy.count(), 2);
   QCOMPARE( activeChangedSpy.at(0).at(0).toInt(), 1);
   QCOMPARE( activeChangedSpy.at(1).at(0).toInt(), 0);
}

void test_ActionListController::testRemoveActiveItem()
{
   QSignalSpy activeChangedSpy( m_actionController, SIGNAL(activeRowChanged(int)) );

   m_model->addMediaFile("c:/Fake/Path/track1.mp3");
   m_actionController->activateRequest( m_model->index(0));
   m_model->removeRow( 0);

   QCOMPARE( activeChangedSpy.count(), 2);
   QCOMPARE( activeChangedSpy.at(0).at(0).toInt(), 0);
   QCOMPARE( activeChangedSpy.at(1).at(0).toInt(), ActionListController::NoItemActive);
}

void test_ActionListController::testRemoveWithNoneActive()
{
   QSignalSpy activeChangedSpy( m_actionController, SIGNAL(activeRowChanged(int)) );

   m_model->addMediaFile("c:/Fake/Path/track1.mp3");
   m_model->addMediaFile("c:/Fake/Path/track2.mp3");
   m_model->removeRow( 1);

   QCOMPARE( activeChangedSpy.count(), 0);
}
